package org.opens.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.opens.dao.StudentDao;
import org.opens.entity.Student;
import org.opens.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Date 2020/12/30 21:20
 * @Created by 99126
 */
@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentDao studentDao;

    @Override
    public List<Student> findByCondition(Student student) {
        Assert.notNull(student);
        if (StrUtil.isNotBlank(student.getName())) {
            student.setName("%" + student.getName() + "%");
        }
        return studentDao.findByCondition(student);
    }

    /**
     * 说明：
     * - 这里将相同值的字段过滤掉了，相同的值不会再次更新，使用的反射机制。
     */
    @Override
    public int dynamicUpdate(Student student) {
        Assert.notNull(student, "更新对象不能为null");
        Assert.notNull(student.getId(), "更新对象的id不能为null");

        Student studentDb = studentDao.selectById(student.getId());
        if (studentDb == null || studentDb.equals(student)) {
            System.out.println("完全相等，不更新");
            return 0;
        }

        String setMethodPrefix = "set";
        String getMethodPrefix = "get";
        String primaryKeyFieldName = "id";
        Method[] declaredMethods = Student.class.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            declaredMethod.setAccessible(true);
            if (declaredMethod.getName().startsWith(getMethodPrefix)) {
                Object value1 = null;
                Object value2 = null;
                try {
                    value1 = declaredMethod.invoke(student);
                    value2 = declaredMethod.invoke(studentDb);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                String getMethodSuffix = StrUtil.removePrefix(declaredMethod.getName(), getMethodPrefix);
                if (value1 == null && value2 == null) {
                    continue;
                }
                // 过滤id属性不设置null，否则会导致update student SET name = '98765432' , create_date = '2020-08-11T00:00:00.000+0800' where id = NULL
                if (getMethodSuffix.equalsIgnoreCase(primaryKeyFieldName)) {
                    continue;
                }
                if (value1 != null && value1.equals(value2)) {
                    try {
                        Class<?> aClass = value1.getClass();
                        // 处理异常java.lang.NoSuchMethodException: org.opens.entity.Student.setCreateDate(cn.hutool.core.date.DateTime)
                        if (value1 instanceof Date) {
                            aClass = Date.class;
                        }
                        Method setMethod = Student.class.getDeclaredMethod(setMethodPrefix + getMethodSuffix, aClass);
                        setMethod.setAccessible(true);
                        setMethod.invoke(student, new Object[]{null});
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return studentDao.dynamicUpdate(student);
    }

    @Override
    public Optional<Student> findById(int id) {
        return Optional.ofNullable(studentDao.selectById(id));
    }

    @Override
    public List<Student> chooseSelect(Student student) {
        Assert.notNull(student, "查询参数不可为null");

        return studentDao.chooseSelect(student);
    }

    @Override
    public List<Student> findByIds(Collection<Integer> ids) {
        Assert.notEmpty(ids, "id集合不能为空");
        return studentDao.findByIds(ids);
    }

    @Override
    public int insertUseMap(Map<String, Object> param) {
        Assert.notEmpty(param);
        return studentDao.insertUseMap(param);
    }

    @Override
    public int batchUpdate(Collection<Student> students) {
        Assert.notEmpty(students);
        return studentDao.batchUpdate(students);
    }

    @Override
    public int batchUpdateFromMysql(Collection<Student> students) {
        Assert.notEmpty(students);
        return studentDao.batchUpdateFromMysql(students);
    }

    @Override
    public Student findByIdInc(int id) {
        return studentDao.findByIdInc(2);
    }
}
